package com.atguigu.gmall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gamll.feign.product.ProductSkuDetailFeignClient;
import com.atguigu.gmall.cart.entity.CartInfo;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.UserAuthUtil;
import com.atguigu.gmall.product.entity.SkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 10574
* @description 针对表【cart_info(购物车表 用户登录系统时更新冗余)】的数据库操作Service实现
* @createDate 2022-12-16 09:36:12
*/
@Slf4j
@Service
public class CartInfoServiceImpl implements CartInfoService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Resource
    ProductSkuDetailFeignClient productFeignClient;

    @Resource
    ThreadPoolExecutor executor;

    @Override
    public String determinCartKey() {
        //获取老请求参数
        HttpServletRequest request = UserAuthUtil.request();
        String userId = request.getHeader(RedisConst.USER_ID_HEADER);
        if (!StringUtils.isEmpty(userId)){
            //用户已经登录
            return RedisConst.CART_INFO_KEY+userId;
        }
        //用户没有登录
        String tempId = request.getHeader(RedisConst.TEMP_ID_HEADER);
        return RedisConst.CART_INFO_KEY+tempId;
    }

    @Override
    public SkuInfo addToCart(Long skuId, Integer num, String cartKey) {
        //判断以前购物车中是否存在该商品
        CartInfo item = this.getItem(cartKey, skuId);
        //没有则添加
        if (item==null){
            CartInfo itemToSave = prepareCartInfo(skuId, num);
            saveItem(cartKey,itemToSave);
            //给前端数据
            SkuInfo skuInfo = getSkuInfo(itemToSave);
            return skuInfo;
        }else {
            //有，修改数据量及其实时价格
            item.setSkuNum(item.getSkuNum()+num);
            item.setUpdateTime(new Date());
            BigDecimal price = productFeignClient.getPrice(skuId).getData();
            item.setSkuPrice(price);
            //保存
            saveItem(cartKey,item);
            SkuInfo skuInfo = getSkuInfo(item);
            return skuInfo;
        }
    }

    private SkuInfo getSkuInfo(CartInfo itemToSave) {
        SkuInfo skuInfo=new SkuInfo();
        skuInfo.setSkuName(itemToSave.getSkuName());
        skuInfo.setSkuDefaultImg(itemToSave.getImgUrl());
        skuInfo.setId(itemToSave.getSkuId());
        return skuInfo;
    }

    private CartInfo prepareCartInfo(Long skuId, Integer num) {
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId).getData();
        CartInfo itemToSave=new CartInfo();
        itemToSave.setSkuId(skuInfo.getId());
        itemToSave.setCartPrice(skuInfo.getPrice());
        itemToSave.setSkuPrice(skuInfo.getPrice());
        itemToSave.setSkuNum(num);
        itemToSave.setImgUrl(skuInfo.getSkuDefaultImg());
        itemToSave.setSkuName(skuInfo.getSkuName());
        itemToSave.setIsChecked(1);
        itemToSave.setCreateTime(new Date());
        itemToSave.setUpdateTime(new Date());
        return itemToSave;
    }

    @Override
    public CartInfo getItem(String cartKey, Long skuId) {

        String json = (String) redisTemplate.opsForHash().get(cartKey, skuId.toString());
        if (!StringUtils.isEmpty(json)){
            return JSON.parseObject(json,CartInfo.class);
        }
        return null;
    }

    @Override
    public void saveItem(String cartKey, CartInfo cartInfo) {
        //单个商品不能超过200
        if (cartInfo.getSkuNum()>=RedisConst.CART_ITEM_NUM_LIMIT) {
            throw new GmallException(ResultCodeEnum.CART_ITEM_NUM_OVERFLOW);
        }


        //总商品类不能超过200
        Long size = redisTemplate.opsForHash().size(cartKey);
        Boolean hasKey = redisTemplate.opsForHash().hasKey(cartKey, cartInfo.getSkuId().toString());
        if (!hasKey){
            if (size+1>=200){
                throw new GmallException(ResultCodeEnum.CART_ITEM_COUNT_OVERFLOW);
            }
        }
        redisTemplate.opsForHash()
                .put(cartKey,cartInfo.getSkuId().toString(),JSON.toJSONString(cartInfo));
    }

    @Override
    public List<CartInfo> cartList(String cartKey) {
        List<CartInfo> cartInfos = redisTemplate.opsForHash()
                .values(cartKey)
                .stream()
                .map(item -> JSON.parseObject(item.toString(), CartInfo.class))
                .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                .collect(Collectors.toList());
        //实时价格
        CompletableFuture.runAsync(()->{
            syncPrice(cartKey, cartInfos);
        },executor);
        return cartInfos;
    }

    private void syncPrice(String cartKey, List<CartInfo> cartInfos) {
        cartInfos
                .stream()
                .forEach(item->{
                    BigDecimal realPrice = productFeignClient.getPrice(item.getSkuId()).getData();
                    if(Math.abs(item.getSkuPrice().doubleValue()-realPrice.doubleValue())>=0.0001){
                        //价格发生变化
                        log.info("购物车：{}，中的商品{}，价格发生变化，最新为：{}", cartKey,item.getSkuId(),realPrice);
                        item.setSkuPrice(realPrice);
                        saveItem(cartKey,item);
                    }
                });
    }

    @Override
    public void updateItemNum(String cartKey, Long skuId, Integer num) {
        CartInfo cartInfo = getItem(cartKey, skuId);
        if(num==1||num==-1){
            cartInfo.setSkuNum(cartInfo.getSkuNum()+num);
        }else {
            cartInfo.setSkuNum(num);
        }
        cartInfo.setUpdateTime(new Date());
        saveItem(cartKey,cartInfo);
    }

    @Override
    public void updateIsCheck(String cartKey, Long skuId, Integer check) {
        if(!(check == 1 || check == 0)){
            throw new GmallException(ResultCodeEnum.INVAILD_PARAM);
        }
        CartInfo item = getItem(cartKey, skuId);
        item.setIsChecked(check);
        item.setUpdateTime(new Date());
        saveItem(cartKey,item);
    }

    @Override
    public void deleteCart(String cartKey, Long skuId) {
        redisTemplate.opsForHash().delete(cartKey,skuId.toString());
    }

    @Override
    public void deleteChecked(String cartKey) {
        //获取购物车
        List<CartInfo> checkeds = getCheckeds(cartKey);
        List<String> skuIds = checkeds.stream()
                .map(item -> item.getSkuId().toString()).collect(Collectors.toList());
        //删除
        redisTemplate.opsForHash().delete(cartKey,skuIds.toArray());
    }

    @Override
    public List<CartInfo> displayCarts() {
        //根据tempId判断缓存中是否有数据
        //1.获取临时id
        String tempCartKey = getCustomeCartKey(RedisConst.TEMP_ID_HEADER);
        //获取用户id
        String userCartKey = getCustomeCartKey(RedisConst.USER_ID_HEADER);

        //用户没有登录直接返回临时购物车数据
        if (userCartKey==null){
            //给临时购物车设置过期时间
            Long expire = redisTemplate.getExpire(tempCartKey);
            if (expire<0){
                redisTemplate.expire(tempCartKey,365, TimeUnit.DAYS);
            }
            return cartList(tempCartKey);
        }

        //用户登录
        try {
            Long tempSize = redisTemplate.opsForHash().size(tempCartKey);
            if (tempSize>0){
                //合并
                List<CartInfo> cartInfos = cartList(tempCartKey);
                for (CartInfo item : cartInfos) {
                    addToCart(item.getSkuId(),item.getSkuNum(),userCartKey);
                }
                //合并结束，删除临时购物车中的数据
                redisTemplate.delete(tempCartKey);
            }
        }catch (Exception e){
            //说明合并期间出错。为了展示依然能进行必须把异常吃掉
        }
        return cartList(userCartKey);
    }

    @Override
    public List<CartInfo> getCheckeds(String cartKey) {
        //获取购物车
        //List<CartInfo> cartInfos = cartList(cartKey);
        List<CartInfo> cartInfos = redisTemplate.opsForHash()
                .values(cartKey)
                .stream()
                .map(item -> JSON.parseObject(item.toString(), CartInfo.class))
                .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                .filter(o1 -> o1.getIsChecked() == 1)
                .collect(Collectors.toList());
        return cartInfos;
    }

    private String getCustomeCartKey(String str){
        HttpServletRequest request = UserAuthUtil.request();
        String header = request.getHeader(str);
        if (StringUtils.isEmpty(str)){
            return null;
        }

        return RedisConst.CART_INFO_KEY+header;
    }
}




